home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / CC_C / 0151.ZIP / EXP.C < prev    next >
Text File  |  1985-02-09  |  23KB  |  914 lines

  1. #include "bdscio.h"
  2.     /*******************************************************
  3. ::    *   CP/M exp. ver.         by F jennings  May 1983     *
  4.     *                                                      *
  5. ::    *            - TELINK -                         *
  6. ::    *        - MODEM PROGRAM -               *
  7.     *                                                      *
  8. ::    *              T. Jennings 29 JAN 1983                 *
  9.     *                                                      *
  10.     *******************************************************/
  11.  
  12. /* Another, but more complete modem program. This one provides
  13. the file transfer modes as in Ward Christensen's programs,
  14. and all the fancy character oriented stuff from TELNET, and
  15. some new ones. */
  16.  
  17. /* Thanks to John Wiardo for 'CMODEM', from whence I got the
  18. basic file transmission stuff, and Leor Zolman et al for the
  19. good text oriented ideas. (And of course the 'C'...) */
  20.  
  21. /* Modem port characteristics. These are set for a FDC-1 teletek */
  22.  
  23. /* You will have to define the following for your system.........*/
  24.  
  25. #define    MSTAT    03    /* Modem status port    */
  26. #define MDATA    02    /* Modem data port    */
  27.  
  28. #define RDA    0x01    /* Modem input data ready mask    */
  29. #define TBE    0x04    /* Modem ready to send a character mask    */
  30.  
  31. /* Cursor control sequences */
  32.  
  33. #define   CLREOL "\033T"    /* string to clear from cursor
  34.                 to end of line. Use 10 or 20 spaces
  35.                 followed by the same amount of 
  36.                 backspaces if not available. */
  37.  
  38. #define  LEADIN    "\033="            /* Lead in sequence for cursor 
  39.                 position.This string is typed 
  40.                 before outputing the line byte. 
  41.                 (See function PLACE(x,y)  */
  42.  
  43. #define    CLEAR_SCREEN "\033*"    /* What else? This is actually 
  44.                 for a TELE-VIDEO 912 terminal.  */
  45.  
  46.    /* Also see place() routine and fix up for your terminal.*/
  47.  
  48. /* * * * * * * * * *   End of custom area.   * * * * * * * * * */
  49.  
  50. #define   NONE 0    /* Usual define area. */
  51. #define   SOH 1
  52. #define   CNTRLB 2
  53. #define   CNTRLC 3
  54. #define   EOT 4
  55. #define   CNTRLE 5
  56. #define   ACK 6
  57. #define   TAB 9
  58. #define   BS 8
  59. #define   LF 0x0a
  60. #define   CR 0x0d
  61. #define   CNTRLQ 17
  62. #define   CNTRLS 19
  63. #define   NAK 21
  64. #define   CNTRLZ 26
  65. #define   DEL 127
  66. #define   TIMEOUT -1
  67. #define      ERROR -1
  68.  
  69. #define   SPECIAL 0x1b        /* ESCape character, */
  70. #define      STOPCHAR 0x1b
  71. #define   CONIN 3
  72. #define   CONOUT 4
  73. #define      BOTTOM 23          /* line where text appears */    
  74. #define   TOP 0               /* line where commands appear */
  75. #define   BSIZE 24096         /* local buffer size, BIG buffer */
  76. #define   ROOM (BSIZE-128)    /* room we use, provide extra space */
  77. #define   CPMSIZ 128          /* CP/M record size, */
  78. #define   RETRYMAX 10         /* # times to retry on tx/rx error */
  79. #define   SPS 275             /* loop iteration fudge factor for
  80.                  time delay  */
  81. /* File Buffers */
  82.  
  83. char filbuf[BUFSIZ];    /* xmit/rcv file buffer */
  84. char txtbuf[BUFSIZ];    /* input text file buffer */
  85. char sndbuf[BUFSIZ];    /* output text file buffer */
  86.  
  87. char colbuf[BSIZE];    /* buffer for text collection (24096) */
  88. char buffer[CPMSIZ];    /* file I/O buffer, */
  89. char linebuf[80];       /* console line input */
  90. char savname[80];    /* text collecttion file name */
  91. char cursor;            /* cursor position (bottom line) */
  92. char c;                 /* general purpose character, */
  93. int ci;        /* character from file I/O, for error checking,*/
  94. int i;                  /* general purpose */
  95. char autolf;        /* if true, send LFs after CR's */
  96. int count;        /* characters in the buffer, */
  97. char halfdup;        /* half/full duplex if true/false */
  98. char savflg;        /* true is collecting text to a file, */
  99. char chksum;        /* file transmission checksum */
  100. char sector;        /* sector being sent/recieved */
  101. char newsec;        /* sector # from the other modem */
  102. int errors;        /* # block transmission errors */
  103. char attempts;        /* another error counter */
  104. char parity;        /* 0= no parity, 1= odd, 2 =even */
  105.  
  106. /* this    is the main driver, where characters are sent back and forth
  107. between    the console and modem. Typing a    special    character allows
  108. processing commands, such as opening files, etc. */
  109.  
  110.  
  111. main()
  112.  
  113. {
  114.  
  115.     cursor =0;        /* initial cursor position, */
  116.     count =0;        /* no text in buf yet, */
  117.     parity =0;
  118.     savflg= FALSE;
  119.     halfdup= FALSE;
  120.     autolf= FALSE;
  121.  
  122.     clear();        /* clear the screen, */
  123.     place(TOP,0); 
  124.     printf("TELINK Modem Utility... by T.Jennings Jan 1983");
  125.     PRINTF("  Hit ESCape to enter commands.");
  126.     signon();            /* sign    on msg,    etc */
  127.     place(BOTTOM,0);
  128.     linebuf[0]= 0x00;        /* empty command line, */
  129.     while(1) {
  130.        if(c= keyhit()) {    /* if console char ready,*/
  131.         if(c== SPECIAL)    /* if its the special command char,*/
  132.         process();        /* go execute commands */
  133.     else {            /* otherwise, */
  134.         if(halfdup)    /* if half duplex mode, */
  135.         conout(c);     /* echo it, */
  136.         modout(c);    /* always send it to the modem,    */
  137.     
  138.     if((savflg) && (halfdup) &&(c != CNTRLZ)) {
  139.         colbuf[count++] =c;
  140.         }
  141.     if(( c==CR) && autolf) {
  142.         modout(LF);
  143.             if(halfdup && autolf) {
  144.             conout(LF);
  145.         }
  146.             if(savflg) {
  147.             colbuf[count++] =LF;
  148.             }
  149.         }
  150.     }
  151. }
  152. if(modstat())    {            /* if modem ready, */
  153.    c= modin(10);            /* get the character, */
  154.       conout(c);            /* type it, */
  155.     if(savflg &&(c != CNTRLZ)) {
  156.         colbuf[count++] =c;     /* save the character */
  157.  
  158.     if(count > ROOM ) {        /* if nearly full, */
  159.         modout(CNTRLS);     /* tell sender to pause, */
  160.                  /* but flush up to 32 chars while he */
  161.                     /* gets around to stopping */
  162.     for(i=0; i<32;    i++)    {
  163.         ci=modin(50);
  164.         if(ci !=TIMEOUT) {
  165.             c= ci;
  166.             colbuf[count] =ci;
  167.             conout(colbuf[count++]);
  168.             }
  169.             else break;
  170.         }            /* write them out to the file, */
  171.     for(i=0; i<count; i++) {
  172.         errors = putc(colbuf[i],txtbuf);
  173.         if(errors ==ERROR)
  174.             break;
  175.     }
  176.     if(errors ==ERROR) {
  177.     place(TOP,0);
  178.         printf(" *** Disk write error: ");
  179.         stopcollect();
  180.             printf(" ***");
  181.                 }
  182.     count =0;    
  183.                modout(CNTRLQ);      /* OK to send again, */
  184.                 }
  185.             }
  186.         }
  187.     }
  188. }
  189. /* Process special commands. As soon as we enter, (from MAIN), 
  190. put the cursor at the top, and enter commands there. Maintain 
  191. the status line. */
  192.  
  193. process()
  194. {
  195. char c;
  196.  
  197.      place (TOP,0);                /* go to the top of the screen, */
  198.      printf ("TELINK Command: ");      /* clear some space, */
  199.     clreol();
  200.         c= lconin();
  201.              place (TOP,0);
  202.      
  203.      switch(tolower(c)) {
  204.  
  205.      case 'h':
  206.       printf("TELINK Command: Half duplex");
  207.       clreol();
  208.           halfdup =TRUE;
  209.           break;
  210.      case 'f':
  211.           printf ("TELINK Command: Full duplex");
  212.         clreol();
  213.           halfdup =FALSE;
  214.           break;
  215.      case 't':
  216.           transmit();              /* transmit a file, */
  217.           break;
  218.      case 'r':
  219.           recieve();               /* get a file, */
  220.           break;
  221.      case 'c':
  222.           collect();               /* collect text, */
  223.           break;
  224.      case 's':
  225.           stopcollect();
  226.           break;
  227.      case 'd':
  228.           down();                  /* send a text file, */
  229.           break;
  230.      case SPECIAL:
  231.       printf("TELINK Command: ESCape sent.");
  232.       clreol();
  233.           modout(SPECIAL);         /* send a special */
  234.           break;
  235.      case 'q':
  236.           if (savflg) 
  237.                stopcollect();
  238.           place(BOTTOM,0);
  239.              clreol();          
  240.                     place (BOTTOM-1,0);
  241.               exit();            /* closes open files. */
  242.             break;
  243.     case 'a':
  244.         printf ("TELINK Command: Auto linefeed ON");
  245.         clreol();
  246.         autolf =TRUE;        /* auto linefeed mode, */
  247.         break;
  248.     case 'm':
  249.         printf ("TELINK Command: Auto linefeed OFF");
  250.         clreol();
  251.         autolf =FALSE;
  252.         break;
  253.     case 'p':
  254.         set_parity();
  255.         break;
  256.     case '?':
  257.         printf("Status Pending:");
  258.         clreol();
  259.         summary();     
  260.         break;
  261. default:
  262.     printf("TELINK Command: Nothing changed.");
  263.       clreol();
  264.           signon();                /* list the commands */
  265.           break;
  266.      }
  267.      place (BOTTOM,cursor);             /* restore the cursor, */
  268.      return;
  269. }
  270. /* Select a parity option. Parity is calculated in the modem
  271. output routine. */
  272.  
  273. set_parity()
  274. {
  275. char c;
  276.  
  277.     do {
  278.     place (TOP,0); printf ("(E)ven, (O)dd, or (N)o parity:");
  279.         clreol();
  280.         errors = FALSE;
  281.         c = lconin();
  282.         place(TOP,0);
  283.         switch(tolower(c)) {
  284.  
  285.         case 'e':
  286.             parity =1;    /* LSB set, */
  287.             break;
  288.         case 'o':
  289.             parity =2;    /* LSB clear, but byte 
  290.             break;            non-zero, */
  291.         case 'n':
  292.             parity =0;    /* byte zero, */
  293.             break;
  294.         default:
  295.             errors = TRUE;    /* make the guy pick one. */
  296.         }
  297.     }  while (errors);
  298.     return;
  299. }
  300.  
  301. /* get a file through the modem    */
  302.  
  303. recieve()        /* new routine from MS-DOS Ver */
  304. {
  305.  
  306. int i;            /* was char i; here ?? */
  307. char ackchar;
  308. char secchk;
  309. int firstchar;
  310. int blknum;
  311.  
  312.     printf("File to recieve: ");
  313.     clreol();
  314.     if (getstring(linebuf) == NULL)     /* quit if blank line */
  315.         return;
  316.  
  317.     errors = creat(linebuf,filbuf);
  318.     if(errors ==ERROR) {
  319.         place(TOP,0);
  320.         printf("Can't create %s",linebuf);
  321.         clreol();
  322.         return;
  323.     }
  324.     ackchar =NAK;            /* for first time though */
  325.     sector    =0;
  326.     blknum    =0;
  327.         errors =0;
  328.  
  329. /* Loop here for each block. If the first character is SOH its a new 
  330.    block. If it's EOF, there is no more blocks (close files).anything
  331.    else, or a TIMEOUT, is an error, falls through to bottom,
  332.    count errors etc. */
  333.  
  334.     do {
  335.     place(TOP,0); printf("Waiting for block %d: ",blknum);
  336.       clreol();
  337.         modout(ackchar);    /* ACK/NAK from previous sector */
  338.          ackchar=NAK;      /* assume bad, will be changed if good */
  339.  
  340.         do  {
  341.             firstchar = modin(100);
  342.             }
  343.   while(firstchar !=SOH && firstchar !=EOT && firstchar !=TIMEOUT);
  344.     if(firstchar == TIMEOUT) {
  345.         ++errors;
  346.         printf("still waiting...");
  347.             clreol();
  348.         }
  349.  
  350. /* SOH recieved. Assume a new block, and attempt to get the rest of
  351.    the block. We'll time out if nothing recieved.  */
  352.  
  353. if(firstchar == SOH) {            /* start of header, */
  354.     newsec = modin(10);
  355.     if(newsec +modin(10)==255) {    /* if correct sector, */
  356.        secchk =sector+1;
  357.         if(newsec == secchk) {
  358.             chksum = 0;
  359.  
  360.             for(i =0; i < CPMSIZ; i++) {
  361.                   buffer[i] = modin(10);   /* read bytes */
  362.                 chksum +=buffer[i];
  363.                            }
  364.         if(chksum == modin(10))    {
  365.            errors = 0;
  366.             ackchar =ACK;
  367.                 sector =newsec;
  368.                 ++blknum;
  369.  
  370.         i = write(filbuf,buffer,1);
  371.             if(i ==ERROR) {
  372.  
  373.             errors =RETRYMAX;
  374.                 printf("Disk write error: ");
  375.                 break;
  376.             }
  377.         printf("received OK");
  378.     }
  379.          else {
  380.             printf("checksum error");
  381.             ++errors;
  382.             }
  383.     } 
  384. else if(newsec == sector) {        /* same sector as last */
  385.     while(modin(10) != TIMEOUT);    /* flush bytes    */
  386.         printf("duplicate sector %d, ignored.",blknum);
  387.         ackchar =ACK;
  388.             }
  389.             else {
  390.               printf("block sync error");
  391.               ++errors;
  392.             }
  393.         } 
  394.         else {      
  395.             printf("header error");
  396.                 ++errors;
  397.             }
  398.         }
  399.     if(errors) {
  400.        while(modin(10) != TIMEOUT);    /* flush any extra, */
  401.         }
  402.         if (keyhit() ==STOPCHAR) {
  403.             errors =RETRYMAX;
  404.         } 
  405.     if (errors >= RETRYMAX) {
  406.       place(TOP,0);
  407.         if(ask("Abort or errors: try again? ")) {
  408.         errors =0;        /* lets try again */
  409.            ackchar =NAK;
  410.             }
  411.         }
  412.     }
  413.     while(firstchar != EOT && errors < RETRYMAX);
  414.        modout(ACK);
  415.  
  416.             fclose(filbuf);
  417.             place(TOP,0);
  418.  
  419.     if((firstchar == EOT) && (errors < RETRYMAX)) {
  420.         printf("Transfer complete, %d blocks received.",blknum);
  421.         clreol();
  422.     }
  423.     else {
  424.     printf("Transfer aborted at block %d.",blknum);
  425.         clreol();
  426.     }
  427.     return;
  428. }
  429. /* Transmit a file down    the wire. This transmits in full Ward Cristensen
  430. block format. */
  431.  
  432. transmit()        /* new */
  433. {
  434. char eof;
  435. char c;
  436. int  i;
  437. int  ci;
  438. char sector;
  439. char chksum;
  440. int blknum;
  441.  
  442.     printf("File to send: ");
  443.     clreol();
  444.     if (getstring(linebuf) == NULL)
  445.         return;
  446.     errors = fopen(linebuf,filbuf);
  447.         if(errors ==ERROR) {
  448.             place(TOP,0);
  449.             printf("Can't find %s!",linebuf);
  450.             clreol();
  451.         return;
  452.     }
  453.     place(TOP,0); printf("Waiting for the receiver, ");
  454.     clreol();
  455.     for (i=RETRYMAX; i > 0; i--) {
  456.         if ((ci =modin(40)) ==NAK) /* wait for initial NAK */
  457.             break;
  458.     }
  459.     if (i == 0) {
  460.         printf(" not ready.");    /* never got it. */
  461.         return;
  462.     }
  463.     errors =0;            /* reset the error counter, */
  464.     eof =FALSE;
  465.     sector =1;            /* sector starts at 1, */
  466.     blknum =0;
  467.  
  468. while(!eof && (errors < RETRYMAX)) {    /* while more chars, */
  469.    i =read(filbuf,buffer,1);        /* fill buffer, */
  470.     eof = (i == NONE);        /* one block only */
  471.         do {            /* until we get an ACK, */
  472.         place(TOP,0); printf("Sending block %d, ",blknum);
  473.         clreol();
  474.         modout(SOH);        /* tell rcvr a block comes */
  475.         modout(sector);        /* send block #, */
  476.         modout(~sector);    /* block check, */
  477.         chksum =0;
  478.            for(i =0;i < CPMSIZ; i++) {
  479.             c=buffer[i];
  480.             modout(c);    /* send 128 data bytes, */
  481.             chksum += c;    /*(keep check sum) */
  482.         }
  483.         modout(chksum);        /* send check sum, */
  484.         i =RETRYMAX;
  485.         do { ci =modin(50);     /* get the acknowledge char*/
  486.         }  while ((ci == TIMEOUT) && --i);
  487.         ++errors;        /* assume bad for now */
  488.         if (keyhit() ==STOPCHAR) {
  489.             errors =RETRYMAX;     /* abort now */
  490.             ci =TIMEOUT;    /* so it falls thru */
  491.         } 
  492.         if (errors >= RETRYMAX) {
  493.             if (ask("Abort or errors: try again?") ) {
  494.                  errors =0;
  495.             }
  496.         }
  497.     } while((ci != ACK) && (errors < RETRYMAX));
  498.  
  499. /* Either block sent OK or too many errors. */
  500.  
  501.     if (ci ==ACK) {
  502.         errors =0;        /* sent OK, */
  503.         printf(" transmitted OK ");
  504.         sector++;        /* next sector... */
  505.         ++blknum;
  506.         }
  507.     }
  508.     modout(EOT);        /* end of transmission */
  509.     modout(EOT);
  510.         
  511.     attempts = 0;
  512.         while(modstat()) {
  513.         modin(10);
  514.             attempts++;
  515.         }
  516.     place (TOP,0);
  517.     if((errors < RETRYMAX) && (attempts < RETRYMAX))
  518.         printf("Transfer complete, sent %d blocks.",blknum);
  519.     else printf("Transfer aborted at block %d.",blknum);
  520.         clreol();
  521.         fclose (filbuf);
  522.     return;
  523. }
  524.  
  525. /* Start the collection of ASCII data over the wire. create a file,
  526. set the flag so that the MAIN will save characters. */
  527.  
  528. collect()        /* new */
  529. {
  530.  if(savflg) {
  531.     printf("Already collecting in file '%s'",savname);
  532.         clreol();
  533.     }
  534.      else    {
  535.         printf("File to put text in: ");
  536.         clreol();
  537.         if (getstring(linebuf) == NULL)
  538.             return;
  539.  
  540.         strcpy(savname,linebuf);    /*save the filename */
  541.                         /*for status display */
  542.         errors = fcreat(linebuf,txtbuf);
  543.     if (errors ==ERROR) {
  544.             place(TOP,0); printf("Can't create %s",linebuf);
  545.             clreol();
  546.             return;
  547.         }
  548.          else 
  549.             savflg =TRUE;        /* enable collection */
  550.             count =0;        /* empty so far, */
  551.         }
  552.         return;
  553.     }
  554.  
  555. /* Stop collection, if any is under way. */
  556.  
  557. stopcollect()            /* old */
  558. {
  559. int i;
  560.  
  561. if(savflg) {            /*if chsracters left in the */
  562.     if(count)   {        /* local buffer, write them */
  563.     for(i=0; i<count; i++) {    /* out */
  564.         putc(colbuf[i],txtbuf);
  565.         }
  566.     }
  567.     putc(CNTRLZ,txtbuf);        /* was space */
  568.       fflush(txtbuf);
  569.        fclose(txtbuf);
  570.         savflg =FALSE;
  571.          printf("Collection stopped");
  572.     clreol();
  573.     }
  574.      else
  575.         printf("Not collecting!");
  576.         clreol();
  577.         return;
  578. }
  579.  
  580. /* Send a text file to the modem, no format. After sending a CR or LF,
  581. we wait for any prompts or CR LF sequences sent by the other
  582. end to go away, allowing downloading messages to bulletin boards,*/
  583.  
  584. down()            /* new */
  585. {
  586. char lastc,b,c;
  587. int ci;
  588. char stopflg;
  589.  
  590.     printf("Text file to send: ");
  591.     clreol();
  592.     if (getstring(linebuf) == NULL)
  593.         return;
  594.  
  595.     errors = fopen(linebuf,sndbuf);
  596.     if(errors == ERROR) {
  597.         place(TOP,0); printf("Can't find '%s'",linebuf);
  598.         clreol();
  599.         return;
  600.     }
  601.     place(BOTTOM,cursor);        /* put the cursor back */
  602.     lastc = CR;            /* in case 1st char is a CR, */
  603.     stopflg = FALSE;
  604. while(((ci=getc(sndbuf))!=ERROR)&&((ci &0x7f) !=CNTRLZ) && !stopflg) {
  605.     c =ci &0x7f;
  606.       if(keyhit() == SPECIAL)
  607.         stopflg =TRUE;        /* abort if ESCape */
  608.         if((c==CR) &&(lastc==CR))    /* dont allow blank lines, */
  609.         modout(' ');        /* make at least 1 char */
  610. if((c !=LF) || autolf) {     /* totally ignore LF's,unless auto lf, */
  611.     modout(c);            /* send the character,    */
  612.         if(halfdup) {        /* echo it to the console, */
  613.         conout(c);        /* explicitly if halfdup, */
  614.     }
  615.         else {
  616.             b =modin(1);
  617.             if(b ==CNTRLS) {
  618.             b =wait();
  619.             }
  620.             conout(b);
  621.         } 
  622.         lastc =c;
  623.         if(lastc ==CR) {    /* if we just did a newline, */
  624.         do {
  625.         ci =modin(2);        /* flush all the prompt or */
  626.            if(ci == CNTRLS) 
  627.             ci =wait();     /* watch for cntrl-S, */
  628.             conout(ci);    /* whatever */
  629.             } 
  630.         while(ci != TIMEOUT);
  631.         }
  632.     if(modstat()) {        /* always look for modem characters, */
  633.         b =modin(1);
  634.         if(b ==CNTRLS)         /* if we get a control S, */
  635.             b =wait();        /* pause here, */
  636.             conout(b);    /* then type it */
  637.             }
  638.         }
  639.     }
  640.     place(TOP,0);
  641.     printf("%s",(stopflg ? "Aborted" : "Transfer complete"));
  642.     clreol();
  643.      return;
  644. }
  645.  
  646. /* Initialize the console, list the commands, etc. */
  647.  
  648. signon()        /* new */
  649.  {
  650.    place (TOP+1,0); clreol(); printf("\n"); clreol();
  651.  
  652. printf("    H ......... Half Duplex      F .......... Full duplex\n");
  653. clreol();
  654. printf("    A ......... Auto linefeed    M ....... Disable Auto linefeed\n");
  655. clreol();
  656. printf("    C ......... Collect text     S ....... Stop collecting text\n");
  657. clreol();
  658. printf("    T ......... Transmit a file  R .......... Receive a file\n");
  659. clreol();
  660. printf("    D ......... Dump text        ESC ........ Send an Escape\n");
  661. clreol();
  662. printf("    P ......... Select Parity    Q ............. Quit\n");
  663. clreol();
  664. printf("    ? ......... List Status      Any char....Reprints commands\n");
  665. clreol();     return;
  666. }
  667.  
  668. /* List the current setting of things. */
  669.  
  670. summary() {            /* new */
  671.  
  672.     place(TOP+1,0); clreol(); printf("\n"); clreol();
  673. printf("        TELINK -- Modem Utility (C) T. Jennings 1983\n");
  674. clreol();printf("\n");clreol();
  675. printf("\tAuto linefeed %s\n",(autolf ? "ON" : "OFF"));
  676. clreol();
  677. if (savflg) {
  678. printf("\tCollecting Text in File '%s'\n",savname);
  679. } else
  680.     printf("\tNot Collecting Text...   \n");
  681. clreol();
  682. printf("\tThe Cursor is at Column %d\n",cursor+1);
  683. clreol();printf("\n");clreol();return;
  684. }
  685.  
  686. /* Console character input, output, and status functions. */
  687.  
  688. char lconin()        /* new original ver */
  689. {
  690.     do(c = keyhit());
  691.     while(c ==0);
  692.     return (c);
  693. }
  694.  
  695. char lconout(c)        /* new */
  696. char c;
  697. {    bdos(6,c);
  698.     return;
  699. }
  700.  
  701. /* Type a character on the console, maintaining correct cursor
  702.    position. All of the seperate returns are to speed things up,
  703.    so it doen't have to go by all of the IF's to get a return
  704.    at the end. */
  705.  
  706. conout(c)
  707. char c;
  708. {    c&= 0x7f;        /*make into ASCII range */
  709.     if (c == ESC)        /* don't send ESCapes,they */
  710.         return;        /* make a mess of the screen */
  711.     if (c == CNTRLZ)    /* same with ^Z, they erase the */
  712.         return;        /* screen on ADM-3',TVI's etc. */
  713.  
  714.     if (c == TAB) {        /* expand tabs to spaces, */
  715.        do conout(' ');    /* every eight columns. */
  716.        while (cursor % 8);    /* (cursor)=mudolo 8 */
  717.         return;        /* this is recursion... */
  718.     }
  719.     lconout(c);        /* type a character */
  720.  
  721.     if ((c > 0x1f) && (c < 0x7f)) {
  722.         ++cursor;    /* update cursor if printable */
  723.         return;
  724.     }
  725.     if ((c == CR) || (c == LF)) {
  726.         cursor =0;    /* column 0 if CR or LF */
  727.         return;
  728.     }
  729.     if ((c == BS) && cursor != 0)
  730.         --cursor;    /* do backspace, to */
  731.     return;
  732. }
  733.  
  734. /* Modem routines: modin, modout, modstat. MODIN is strange, 
  735. since it supports a maximum timeout argument. */
  736.  
  737. char modstat()
  738. {
  739. char c;
  740.      c = inp(MSTAT);            /* sample status, */
  741.      return(c&RDA);
  742. }
  743. /* Output a character to the modem. If the parity flag is set, 
  744. calculate parity. Parity is accumulated in the LSB of P; the other
  745. bits contain garbage. The values of 'parity' are chosen to accomodate
  746. this method: Add all the one bits together, adding in the parity
  747. flag. The sum of the data bits is 1 if there are an odd number of
  748. bits. Adding the parity flag (assume set to 'odd') leaves 0 as the 
  749. parity flag. Conversly, if even parity is selected ('parity' =1)
  750. adding 1 to the sum of the data bits (1) makes a 0 parity bit. */
  751.  
  752. char modout(c)
  753. char c;
  754. {
  755. char s;
  756. int p,b,i;
  757.  
  758.     if (parity) {
  759.         p = parity; b=c;         /* initially 1 if even desired, */
  760.         for(i=0; i<7; i++) {    /* do 7 bits, */
  761.             p+=b;        /* accumulate bits in p, */
  762.         b = (b >> 1);        /* next bit, */
  763.     }                /* now lsb of P=1 means even */
  764.     c &= 0x7f;            /* strip off MSB, */
  765.     c |= ((p <<7) &0x80);      /* set/reset MSB with parity flag */
  766.     }
  767.          do {
  768.         s = inp(MSTAT) &TBE;
  769.     }
  770.         while (s==0);
  771.         outp (MDATA,c);         /* then send it */
  772.     return;
  773. }
  774. /* get a character from the modem, but wait a maximum of (seconds) 
  775. tenths of a second. Return TIMEOUT on end.  */
  776.  
  777. int modin(tenths)
  778. int  tenths;
  779. {
  780. char c;
  781.          tenths *=SPS;              /* make into loop count, */
  782.   while ( !((c=inp(MSTAT)) &RDA) && --tenths);        /* counter */
  783.      if (tenths ==0) 
  784.           return (TIMEOUT);
  785.     else return(inp(MDATA));        /* get the char, */
  786. }
  787. /* appends [Y/N] to question asked, returns TRUE if yes. */
  788.  
  789. int ask(question)
  790. char *question;
  791. {
  792. char c;
  793.     printf ("%s [ Y/N ]",question);
  794.     clreol();
  795.         while (1) {
  796.             c = lconin();
  797.             if(tolower(c) == 'y')
  798.                 return(TRUE);
  799.             if(tolower(c) == 'n')
  800.                 return (FALSE);
  801.         }
  802. }
  803.  
  804. /* Wait until any character but control-S is detected, and return it.
  805.    Watch the keyboard for a break too. */
  806.  
  807. char wait()
  808. {
  809. int w;
  810.     w =CNTRLS;
  811.  
  812.     while (w ==CNTRLS) {
  813.         if (modstat())
  814.             w =modin(1);
  815.         if (keyhit() ==STOPCHAR)
  816.             w =STOPCHAR;
  817.     }
  818.     return (w);
  819.  
  820. }
  821.  
  822. /* Cursor positioning routines. */
  823.  
  824. /* Clear the screen, leave the cursor at the BOTTOM,left. */
  825.  
  826. int clear()
  827. {
  828. int i;
  829.     place(BOTTOM,0);        /* put the cursor at bottom. */
  830.         for(i=0; i<26; i++)
  831.         lconout('\n');
  832.     return;
  833. }
  834.  
  835. /* Function PLACE at 'line' and 'column'. Lines are numbered 0-23 from
  836.  top to bottom, columns 0-79 from left to right. make sure this 
  837.  routine is correct for your terminal. */
  838.  
  839. place(line,column)            /* line, column */
  840. char line,column;            /* coordinates */
  841. {
  842.     printf("%s%c%c",LEADIN,line+32,column+32);
  843.         return;
  844. }
  845.  
  846. /* If a key is hit, return the key, else 0 */
  847.  
  848. char keyhit()
  849. {
  850.     return(bdos(6,0xff));
  851.  
  852. }
  853.  
  854. clreol()
  855. {
  856.     printf("%s",CLREOL);
  857.     return;
  858. }
  859.  
  860. /* Get an input string; return NULL if error or empty line. Provide the
  861. usual minimum editing capabilities.  */
  862.  
  863. getstring(string)
  864. char string[];
  865. {
  866. int count;
  867. char c;
  868.     count= 0;
  869.     while (1) {
  870.  
  871.         c= lconin();        /* get a character, */
  872.           switch (c) {
  873.         case CR:        /* process it, */
  874.         case LF:
  875.            string[count]= 0x00;    /* terminate string, */
  876.             return(count);    /* return string length */
  877.             break;
  878.  
  879.         case 0x08:
  880.         case 0x7f:        /* delete character */
  881.         case 0x13:
  882.             if (count) {
  883.                 --count;    /* one less char, */
  884.                 printf("\010 \010");
  885.             }
  886.             break;
  887.             case 0x18:
  888.         case 0x15:            /* delete line */
  889.         case 0x19:
  890.         case 0x03:
  891.             while (count) {
  892.                 --count;
  893.                 printf("\010 \010");
  894.             }
  895.             break;
  896.         case 0x12:            /* retype line, */
  897.             while (string[count]) {
  898.                 lconout(string[count++]);
  899.             }
  900.             break;
  901.         default:            /* insert character */
  902.                 if ((c > 0x1f) && (count < 80) ) {
  903.                 string[count++] =toupper(c);
  904.                 string[count]= 0x00;
  905.                 lconout(c);
  906.             } else
  907.                 lconout(0x07);
  908.             break;
  909.         }
  910.     }
  911. }
  912.                      /* end */
  913.  
  914.